import 'dart:async';
import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/flame.dart';
import 'package:flutter/material.dart';
import '../mahjong_game.dart';
import '../util/user_location.dart';
import 'common_util.dart';
import 'mahjong_context.dart';

/// 注意composition的 position 是对象的中心坐标
typedef CardClickFun = bool Function(CommonCard current);

bool defaultClick(CommonCard current) {
  return !current.selected;
}

/// *
/// 显示出来的牌
/// 通用类
class CommonCard extends PositionComponent
    with TapCallbacks, HasGameRef<MahjongIndexGame>
    implements Comparable<CommonCard> {
  CardClickFun? cardClick;
  Image? topImageCache, bottomImageCache, rightImageCache, leftImageCache;
  bool mark;
  int index;
  Color focusColor;
  bool showTips;
  bool handCard = false;
  bool queTag = false;
  // 是否为癞子
  bool laiTag = false;

  CommonCard(
      {super.size,
      super.position,
      super.scale,
      this.index = 0,
      this.showTips = false,
      this.backgroundSrc = 'mahjong/user/bottom/usercard_background.png',
      this.cardImageRotation = 0,
      this.drift = false,
      // 是否可以点击
      this.isOnClick = false,
      this.isDisk = true,
      this.handCard = false,
      // 所属方向
      required this.cardDirection,
      this.pointToDirection,
      // 遮掩层
      this.focus = false,
      this.focusColor = const Color.fromARGB(144, 173, 173, 173),
      // 钻石
      this.mark = false,
      // 点击事件
      this.cardClick,
      // 是否为缺牌
      this.queTag = false,
      // 是否为癞子
      this.laiTag = false,
      required this.cardCode});
  int cardCode;
  double cardImageRotation;
  Rect? backGroundRect;
  String backgroundSrc;
  bool focus;

  Direction cardDirection;

  //指向谁
  Direction? pointToDirection;

  //是否上移 图面文字
  bool drift;
  Vector2 markPosition = Vector2.all(0);

  Vector2 markSize = Vector2.all(0);

  // 是否为桌面的牌
  bool isDisk;

  // 是否可点击
  bool isOnClick;
  bool selected = false;
  Vector2? cardImageSize;
  Vector2? cardImagePosition;

  Tween<double>? tween;

  double speedY = 30.0;

  SpriteComponent? diamondCompon;

  var pointToImage;
  var diamondImage;
  var mjBgImage;
  @override
  FutureOr<void> onLoad() {
    super.onLoad();
    cardClick ??= defaultClick;
    diamondImage = Flame.images.fromCache('mahjong/commons/diamond.png');
    mjBgImage = Flame.images.fromCache(backgroundSrc);
    if (cardCode > 29 || cardCode <= 0 || cardCode == 10 || cardCode == 20) {
      cardCode = 1;
    }
    Direction? result =
        LocationUtil.getCardPointTo(cardDirection, pointToDirection);
    if (result != null) {
      pointToImage =
          Flame.images.fromCache(LocationUtil.cardPointToImage[result]!);
    }

    backGroundRect = Rect.fromLTWH(0, 0, size.x, size.y);

    if (cardDirection == Direction.LEFT) {
      cardImagePosition = Vector2(
          0,
          size.y / 2 -
              size.x *
                  MahjongContext().lrExportCardBgAndImageRatio /
                  MahjongContext().cardImageWHRatio /
                  2);
      cardImageSize = Vector2(
          size.x * MahjongContext().lrExportCardBgAndImageRatio,
          size.x *
              MahjongContext().lrExportCardBgAndImageRatio /
              MahjongContext().cardImageWHRatio);
    } else if (cardDirection == Direction.RIGHT) {
      cardImagePosition = Vector2(
          size.x * (1 - MahjongContext().lrExportCardBgAndImageRatio),
          size.y / 2 -
              size.y * MahjongContext().lrExportCardBgAndImageRatio / 2);
      cardImageSize = Vector2(
          size.x * MahjongContext().lrExportCardBgAndImageRatio,
          size.y * MahjongContext().lrExportCardBgAndImageRatio);
    }

    if (mark) {
      addMark();
    }
  }

  void addMark() {
    diamondCompon = SpriteComponent(sprite: Sprite(diamondImage));
    switch (cardDirection) {
      case Direction.LEFT:
        markSize =
            Vector2.all(size.x * MahjongContext().lrExportCardBgAndImageRatio);
        markPosition = Vector2(0, size.y - (size.y - markSize.x) / 2);
        diamondCompon?.angle = radians(-90);
      case Direction.RIGHT:
        markSize = Vector2.all(MahjongContext().lrExportCardSize.x *
            MahjongContext().lrExportCardBgAndImageRatio);
        markPosition = Vector2(size.x, (size.y - markSize.x) / 2);
        diamondCompon?.angle = radians(-270);
      default:
        markSize = Vector2.all(MahjongContext().lrExportCardSize.x *
            MahjongContext().lrExportCardBgAndImageRatio);
        markPosition = Vector2((size.x - markSize.x) / 2, 0);
    }
    diamondCompon!.position = markPosition;
    diamondCompon!.size = markSize;
    add(diamondCompon!);
  }

  void removeMark() {
    diamondCompon?.removeFromParent();
    diamondCompon = null;
  }

  @override
  bool containsLocalPoint(Vector2 point) {
    return Rect.fromLTWH(0, 0, size.x, size.y)
        .contains(Offset(point.x, point.y));
  }

  @override
  void render(Canvas canvas) {
    if (showTips) {
      var gradient = const LinearGradient(
        begin: Alignment.centerLeft,
        end: Alignment.centerRight,
        colors: [
          Color.fromARGB(255, 255, 102, 0),
          Color.fromARGB(255, 234, 248, 35),
          Color.fromARGB(255, 255, 102, 0),
        ],
      );
      double hintWidth = size.x / 4;
      final paint = Paint()
        ..shader = gradient.createShader(Rect.fromPoints(
            Offset((size.x - hintWidth) / 2, -hintWidth * 2),
            Offset(size.x - (size.x - hintWidth) / 2, -hintWidth)));
      final path = Path()
        ..moveTo((size.x - hintWidth) / 2, -hintWidth * 2) // bottom left corner
        ..lineTo(size.x - (size.x - hintWidth) / 2,
            -hintWidth * 2) // bottom right corner
        ..lineTo(size.x / 2, -hintWidth) // top center
        ..close(); // close the path to form a triangle

      canvas.drawPath(path, paint);
    }
    // 背景开始
    SpriteComponent(
            sprite: Sprite(mjBgImage), size: size, position: Vector2.all(0))
        .render(canvas);
    // 万条筒   牌面开始
    double cardTopImageWidth = size.x - (size.x / 6);
    double cardTopImageHeight = cardTopImageWidth * 1.30;

    var paiMainImage =
        Flame.images.fromCache(CommonUtil.getCardImage(cardCode));
    var cardChartImageSize = cardImageSize ??
        Vector2(
          cardTopImageWidth,
          cardTopImageHeight,
        );
    var cardChartImagePosition = cardImagePosition ??
        Vector2((size.x - cardTopImageWidth) / 2,
            drift ? 0 : 0 + (size.y - cardTopImageHeight));
    Sprite(paiMainImage).render(canvas,
        position: cardChartImagePosition, size: cardChartImageSize);

    // 缺牌还是癞子 开始
    if (laiTag || queTag) {
      String tagImage = "mahjong/card/${laiTag ? 'lai' : 'que'}.png";
      var paiMianTagImage = Flame.images.fromCache(tagImage);
      Sprite(paiMianTagImage).render(canvas,
          position: Vector2(0, cardChartImagePosition.y),
          size: cardChartImageSize);
    }
    // 卡牌上的指向
    if (pointToImage != null) {
      Sprite(pointToImage).render(canvas,
          position:
              cardChartImagePosition + (cardChartImageSize - size / 2) / 2,
          size: Vector2.all(size.x / 2));
    }

    if (!isDisk && !isOnClick) {
      Rect coverRect = Rect.fromLTWH(0, 0, size.x, size.y);
      Paint coverPaint = Paint()
        ..color = const Color(0x4C000000)
        ..style = PaintingStyle.fill;
      canvas.drawRect(coverRect, coverPaint);
    }
    if (focus) {
      RRect coverRect =
          RRect.fromLTRBR(0, 0, size.x, size.y, const Radius.circular(3));
      Paint coverPaint = Paint()
        ..color = focusColor
        ..style = PaintingStyle.fill;
      canvas.drawRRect(coverRect, coverPaint);
    }

    super.render(canvas);
  }

  bool cardSelect(bool state) {
    //如果已经是激活状态,就不要再次激活了
    if (selected && state) {
      return selected;
    } else if (!selected && !state) {
      return selected;
    }
    // 选中状态默认是false
    if (state) {
      position.y -= size.y / 4;
    } else if (!state) {
      position.y += size.y / 4;
    }
    selected = !selected;
    return selected;
  }

  @override
  void update(double dt) {
    super.update(dt);
    if (null == diamondCompon) {
      return;
    }
    if (cardDirection == Direction.BOTTOM || cardDirection == Direction.TOP) {
      diamondCompon!.position.y += speedY * dt;
      if (diamondCompon!.position.y < -markSize.x) {
        speedY = speedY.abs();
      } else if (diamondCompon!.position.y > 0) {
        speedY = -speedY.abs();
      }
    } else if (cardDirection == Direction.LEFT) {
      diamondCompon!.position.x += speedY * dt;

      if (diamondCompon!.position.x > 0) {
        speedY = -speedY.abs();
      } else if (diamondCompon!.position.x < -markSize.x) {
        speedY = speedY.abs();
      }
    } else if (cardDirection == Direction.RIGHT) {
      diamondCompon!.position.x += speedY * dt;
      if (diamondCompon!.position.x < size.x) {
        speedY = speedY.abs();
      } else if (diamondCompon!.position.x > size.x + markSize.x) {
        speedY = -speedY.abs();
      }
    }
  }

  @override
  void onTapDown(TapDownEvent event) async {
    if (!isOnClick || focus) {
      return;
    }
    var result = cardClick!(this);
    cardSelect(result);
  }

  @override
  int compareTo(CommonCard other) {
    return cardCode.compareTo(other.cardCode);
  }
}
